﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace Galoap
{
    partial class Game
    {

        /// <summary>
        /// Return all games
        /// </summary>
        /// <returns></returns>
        public static IQueryable<Game> GetAllGames()
        {
            return from game in GaloapDatabase.Database.Game
                   select game;
        }

        /// <summary>
        /// Return a game given an ID
        /// </summary>
        /// <param name="gameID"></param>
        /// <returns></returns>
        public static Game GetGame(int gameID)
        {
            return (from game in GaloapDatabase.Database.Game where game.GameID == gameID select game).First();
        }

        /// <summary>
        /// Return a game given name
        /// </summary>
        /// <param name="gameID"></param>
        /// <returns></returns>
        public static Game GetGame(string gamename)
        {
            return Game.GetAllGames().Where(j => j.Title.Equals(gamename)).First();
        }

        /// <summary>
        ///  List of games that an user has played
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        public static List<Game> GetUserGames(User user)
        {
            return (from game in GaloapDatabase.Database.Game
                    join GameSession in GaloapDatabase.Database.GameSession.Include("User").Include("Game") on game.GameID equals GameSession.Game.GameID
                    where GameSession.User.UserID == user.UserID
                    select game).Distinct().ToList();
        }

        /// <summary>
        /// List of all games that an user has played
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        public static List<Game> GetAllUserGames(User user)
        {
            return (from game in GaloapDatabase.Database.Game
                    join GameSession in GaloapDatabase.Database.GameSession.Include("Game") on game.GameID equals GameSession.Game.GameID
                    where GameSession.User.UserID == user.UserID
                    select game).ToList();
        }

        /// <summary>
        /// List of all games that have been played on a certain day
        /// </summary>
        /// <param name="date"></param>
        /// <returns></returns>
        public static List<Game> GetPlayedGamesByDate(DateTime date)
        {
            return (from game in GaloapDatabase.Database.Game
                    join GameSession in GaloapDatabase.Database.GameSession.Include("Game") on game.GameID equals GameSession.Game.GameID
                    where GameSession.Date.Year == date.Year && GameSession.Date.Month == date.Month && GameSession.Date.Day == date.Day
                    select game).Distinct().ToList();
        }

        /// <summary>
        /// Returns the game that has been played most frequently
        /// </summary>
        /// <returns></returns>
        public static Game GetMostFrequentlyPlayedGame()
        {
            return (from game in GaloapDatabase.Database.Game
                    join GameSession in GaloapDatabase.Database.GameSession.Include("Game") on game.GameID equals GameSession.Game.GameID
                    group game by game.GameID into gameGroup
                    orderby gameGroup.Count() descending
                    select gameGroup).First().First();
        }

        /* public static int GetNumberOfGamesPlayedOnDate(DateTime date)
        {
            return GetGamesPlayedOnDate(date).Count;
        } */ 

        /// <summary>
        /// Returns the list of games with max number of answers
        /// </summary>
        /// <returns></returns>
        public static List<Game> GetGameWithMaxNumberOfAnswers()
        {
            var GameSessions = (from GameSession in GaloapDatabase.Database.GameSession.Include("Answer")
                                group GameSession by GameSession.Answer.Count() into GameSessionGroup
                                orderby GameSessionGroup.Key descending
                                select GameSessionGroup).First();

            return (from GameSession in GameSessions
                    select GameSession.Game).ToList();
        }


        /// <summary>
        /// Returns a set of answers with user ranking above a certain minimum
        /// </summary>
        /// <returns></returns>
        public static List<Answer> GetSetOfAnswers(Game g, float minimum)
        {
            List<Answer> answers = new List<Answer>();
            int counter = 0;
            int max = 0;
            Answer t = null;
            g.Question.Load();
            foreach (Question q in g.Question)
            {
                List<Answer> ans = q.GetDistinctAnswersOrderedByFrequency<Answer>();
                foreach (Answer a in ans)
                {
                    if (max > a.Counter)
                    {
                        max = 0;
                        break;
                    }
                    counter = 0;
                    a.GameSession.Load();
                    foreach (GameSession gs in a.GameSession.ToList())
                    {
                        if (gs.User.GetRankingForGame(g) > minimum)
                            counter++;
                    }
                    if (counter > max)
                    {
                        max = counter;
                        t = a;
                    }
                    else
                    {
                        if (t != null)
                            answers.Add(t);
                        t = null;
                    }
                }
            }
            return answers;
        }

        /// <summary>
        /// Returns the list of the users that have played this game
        /// </summary>
        /// <returns></returns>
        public List<User> GetUsersThatPlayedThisGame()
        {
            this.UserGame.Load();
            return (from userGame in this.UserGame
                    select userGame.User).ToList();
        }

        /// <summary>
        /// Returns the list of the GameSessions with the highest score
        /// </summary>
        /// <returns></returns>
        public List<GameSession> GetGameSessionsWithHighestScore()
        {
            this.GameSession.Load();
            return (from GameSession in this.GameSession
                    group GameSession by GameSession.Score into GameSessionGroup
                    orderby GameSessionGroup.Key descending
                    select GameSessionGroup).First().ToList();
        }

        /// <summary>
        /// Returns all documents associated to questions of this game
        /// </summary>
        /// <returns></returns>
        public List<Document> GetDocuments()
        {
            Question.Load();
            List<Document> gameDocuments = new List<Document>();
            
            foreach (Question q in this.Question)
            {
                q.Document.Load();
                gameDocuments.AddRange(q.Document);
            }
            return gameDocuments;
        }

        /// <summary>
        /// Adds this to the database
        /// </summary>
        public void AddGameToDB()
        {
            GaloapDatabase.Database.AddToGame(this);
            GaloapDatabase.Database.SaveChanges();
        }

        /// <summary>
        /// Saves the current state of this in the database
        /// </summary>
        public void Save()
        {
            GaloapDatabase.Database.SaveChanges();
        }
    }
}
